home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / cups / backend / dnssd < prev    next >
Text File  |  2008-10-20  |  9KB  |  276 lines

  1. #!/usr/bin/perl
  2. # The above Perl path may vary on your system; fix it!!! -*- perl -*-
  3.  
  4. # dnssd - Search for network printers with the avahi-browse command
  5. #         (Zeroconf, DNS-SD)
  6.  
  7. # Printer discovery CUPS backend (like the SNMP backend)
  8. # See also http://qa.mandriva.com/show_bug.cgi?id=21812
  9.  
  10. # Copyright 2007 Till Kamppeter <till.kamppeter@gmail.com>
  11. #
  12. #  This program is free software; you can redistribute it and/or modify it
  13. #  under the terms of the GNU General Public License as published by the
  14. #  Free Software Foundation; either version 2 of the License, or (at your
  15. #  option) any later version.
  16. #
  17. #  This program is distributed in the hope that it will be useful, but
  18. #  WITHOUT ANY WARRANTY; without even the implied warranty of
  19. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
  20. #  Public License for more details.
  21. #
  22. #  You should have received a copy of the GNU General Public License
  23. #  along with this program; if not, write to the Free Software
  24. #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  25. #  USA.
  26.  
  27. # Usage: 
  28. #
  29. # cp dnssd /usr/lib/cups/backend/
  30. # chmod 755 /usr/lib/cups/backend/dnssd
  31. # killall -HUP cupsd (or "/etc/init.d/cups restart", CUPS 1.1.x only)
  32. # lpinfo -v (or use any printer setup tool)
  33. #
  34. # /usr/lib/cups/backend/dnssd <IP address>
  35. #    Shows only info for printer with given IP
  36.  
  37. use strict;
  38.  
  39. $0 =~ m!^(.*)/([^/]+)\s*$!;
  40. my $progname = ($2 || $0 || "dnssd");
  41. my $progpath = ($1 || "/usr/lib/cups/backend");
  42.  
  43. if (@ARGV > 1) {
  44.     die "This backend is only for printer discovery, not for actual printing.\n";
  45. }
  46.  
  47. my $ipfilter = $ARGV[0] if $ARGV[0];
  48.  
  49. my $avahicmd = "avahi-browse -k -t -v -r -a 2> /dev/null";
  50.  
  51. # IPs which are for computers, consider their printer entries as queues
  52. # set up with the local printing system (CUPS, LPD, Windows/Samba SMB, ...)
  53. my @computerips = ();
  54. my $output;
  55. my $hosts;
  56. my ($interface, $nettype, $ip, $host, $make, $model, $description, $cmd, $makemodel, $deviceid, $protocol, $port, $uriext, $uri);
  57.  
  58. open (AVAHI, "$avahicmd |") or exit 0;
  59. while (my $line = <AVAHI>) {
  60.     chomp ($line);
  61.     if ($line =~ /^\s*=\s+(\S+)\s+(\S+)\s+(.*?)\s+(\S+)\s+(\S+)\s*$/) {
  62.     # New item
  63.     $interface = $1;
  64.     $nettype = $2;
  65.     my $itemname = $3;
  66.     my $protocolinfo = $4;
  67.     next if $nettype !~ /^IPv4$/i;
  68.         if ($protocolinfo =~ /_workstation/) {
  69.         $protocol = "computer";
  70.     } elsif ($protocolinfo =~ /_pdl-datastream/) {
  71.         $protocol = "socket";
  72.     } elsif ($protocolinfo =~ /_printer/) {
  73.         $protocol = "lpd";
  74.     } elsif ($protocolinfo =~ /_ipp/) {
  75.         $protocol = "ipp";
  76.     }
  77.     } elsif ($line =~ /^\s*hostname\s*=\s*\[([^\]]+)\]\s*$/) {
  78.     $host = $1;
  79.     $host =~ s/\.local\.?$//;
  80.     } elsif ($line =~ /^\s*address\s*=\s*\[([^\]]+)\]\s*$/) {
  81.     $ip = $1;
  82.     if ($protocol eq "computer") {
  83.         push (@computerips, $ip);
  84.         $protocol = "";
  85.     }
  86.     } elsif ($line =~ /^\s*port\s*=\s*\[([^\]]+)\]\s*$/) {
  87.     $port = $1;
  88.     } elsif ($line =~ /^\s*txt\s*=\s*\[(.+)\]\s*$/) {
  89.     my $info = $1;
  90.     if ($protocol && (!defined($ipfilter) || ($ipfilter eq $ip))) {
  91.         my ($ty, $product, $pdls, $usb_MFG, $usb_MDL, $usb_DES, $usb_CMD) = 
  92.         ("", "", "", "", "", "", "");
  93.         while ($info =~ s/^\s*\"([^\"]+)\"\s*//) {
  94.         my $infoitem = $1;
  95.         if ($infoitem =~ /^([^=]*)=(.*)$/) {
  96.             my $field = $1;
  97.             my $content = $2;
  98.             if ($field eq "ty") {
  99.             $ty = $content;
  100.             } elsif ($field eq "product") {
  101.             $product = $content;
  102.             $product =~ s/^\((.*)\)$/$1/;
  103.             } elsif ($field eq "usb_MFG") {
  104.             $usb_MFG = $content;
  105.             } elsif ($field eq "usb_MDL") {
  106.             $usb_MDL = $content;
  107.             } elsif ($field eq "usb_DES") {
  108.             $usb_DES = $content;
  109.             } elsif ($field eq "usb_CMD") {
  110.             $usb_CMD = $content;
  111.             } elsif ($field eq "rp") {
  112.             $uriext = $content;
  113.             } elsif ($field eq "pdl") {
  114.             while ($content =~ s/^\s*([^\,]+?)\s*\,\s*//) {
  115.                 my $i = $1;
  116.                 if ($i =~ m!\b(postscript|ps)\b!i) {
  117.                 $pdls .= "POSTSCRIPT,";
  118.                 } elsif ($i =~ m!\b(pdf)\b!i) {
  119.                 $pdls .= "PDF,";
  120.                 } elsif ($i =~ m!\b(pcl6|pclxl|pxl)\b!i) {
  121.                 $pdls .= "PCLXL,";
  122.                 } elsif ($i =~ m!\b(pcl[345][ce]?|pcl)\b!i) {
  123.                 $pdls .= "PCL,";
  124.                 }
  125.             }
  126.             $pdls =~ s/\,$//;
  127.             }
  128.         }
  129.         }
  130.         $usb_MDL ||= $ty;
  131.         $usb_DES ||= $product;
  132.         if ($usb_MFG) {
  133.         $make = $usb_MFG;
  134.         } elsif ($usb_DES =~ /^KONICA\s*MINOLTA\b/i) { 
  135.         $make = "KONICA MINOLTA";
  136.         } elsif ($usb_DES) {
  137.         $usb_DES =~ /^\s*(\S*)\b/;
  138.         $make = $1;
  139.         }
  140.         $model = $usb_MDL;
  141.         if (!$model) {
  142.         $usb_DES =~ /^\s*\S*\s*(.*)$/;
  143.         $model = $1;
  144.         }
  145.         $usb_CMD ||= $pdls;
  146.         my $extra;
  147.         if ($protocol eq "socket") {
  148.         if ($port eq "9100") {
  149.             $uri = "socket://$ip";
  150.         } else {
  151.             $uri = "socket://$ip:$port";
  152.         }
  153.         $extra = "Port $port";
  154.         } elsif ($protocol eq "lpd") {
  155.         $uri = "lpd://$ip" . ($uriext ? "/$uriext" : "");
  156.         $extra = ($uriext ? "Queue: $uriext" : "Default queue");
  157.         } elsif ($protocol eq "ipp") {
  158.         $uri = "ipp://$ip:$port" . ($uriext ? "/$uriext" : "");
  159.         $extra = ($uriext ? "Queue: $uriext" : "Default queue");
  160.         }
  161.         if ($make && $model) {
  162.         $make =~ s/Hewlett.?Packard/HP/i;
  163.         $make =~ s/Lexmark.?International/Lexmark/i;
  164.         $model =~ s/Hewlett.?Packard/HP/i;
  165.         $model =~ s/Lexmark.?International/Lexmark/i;
  166.         while ($model =~ s/^\s*$make\s*//i) {};
  167.         $makemodel = "$make $model";
  168.         } elsif ($usb_DES) {
  169.         $makemodel = $usb_DES;
  170.         } else {
  171.         $makemodel = "Unknown";
  172.         }
  173.         $deviceid = ($usb_MFG ? "MFG:$usb_MFG;" : "") .
  174.         ($usb_MDL ? "MDL:$usb_MDL;" : "") .
  175.         ($usb_DES ? "DES:$usb_DES;" : "") .
  176.         ($usb_CMD ? "CMD:$usb_CMD;" : "");
  177.         $deviceid .= "CLS:PRINTER;" if $deviceid;
  178.         $hosts->{$ip} = $host if $host;
  179.         $output->{$ip}{$protocol}{$uriext} =
  180.         "network $uri \"$makemodel\" \"$makemodel $ip ($extra)\" \"$deviceid\"\n";
  181.         ($interface, $nettype, $ip, $host, $make, $model, $description, $cmd, $makemodel, $deviceid, $protocol, $port, $uriext, $uri) =
  182.         ("", "", "", "", "", "", "", "", "", "", "", "", "", "");
  183.     }
  184.     }
  185. }
  186.  
  187. my $localqueues = {};
  188. my $queue = undef;
  189. if (open LPSTAT, "LC_ALL=C lpstat -l -p -v |") {
  190.     while (my $line = <LPSTAT>) {
  191.     chomp $line;
  192.     if ($line =~ /^printer\s+(\S+)/i) {
  193.         $queue = $1;
  194.         $localqueues->{$queue} = {};
  195.     } elsif ($queue) {
  196.         if ($line =~ /^\s+Connection:\s+remote/i) {
  197.         $localqueues->{$queue}{remote} = 1;
  198.         } elsif ($line =~ /^\s+Interface:\s+(\S+)/i) {
  199.         $localqueues->{$queue}{interface} = $1;
  200.         } elsif ($line =~ /^device\s+for\s+(\S+)\s*:\s*(\S+)/i) {
  201.         $localqueues->{$1}{uri} = $2;
  202.         }
  203.     }
  204.     }
  205.     close LPSTAT
  206. }
  207.  
  208. my @localips = ();
  209. if (open IFCONFIG, "LC_ALL=C /sbin/ifconfig |") {
  210.     while (my $line = <IFCONFIG>) {
  211.     chomp $line;
  212.     if ($line =~ /^\s*inet\s+addr:\s*(\S+)/i) {
  213.         push (@localips, $1);
  214.     }
  215.     }
  216.     close IFCONFIG;
  217. }
  218.  
  219. foreach my $ip (keys(%{$output})) {
  220.     # Do not list print queues of the local machine
  221.     next if member($ip, @localips);
  222.     if ($output->{$ip}{"socket"}) {
  223.     foreach my $uriext (keys(%{$output->{$ip}{"socket"}})) {
  224.         if (keys(%{$output->{$ip}{"socket"}}) == 1) {
  225.         $output->{$ip}{"socket"}{$uriext} =~
  226.             s/^(\s*\S*\s*\S*\s*\"[^\"]*\"\s*\"[^\"\(]*?)\s*\([^\)]*\)\s*(\"\s*.*)$/$1$2/;
  227.         }
  228.         print $output->{$ip}{"socket"}{$uriext};
  229.     }
  230.     } elsif ($output->{$ip}{"lpd"}) {
  231.     foreach my $uriext (keys(%{$output->{$ip}{"lpd"}})) {
  232.         if (keys(%{$output->{$ip}{"lpd"}}) == 1) {
  233.         $output->{$ip}{"lpd"}{$uriext} =~
  234.             s/^(\s*\S*\s*\S*\s*\"[^\"]*\"\s*\"[^\"\(]*?)\s*\([^\)]*\)\s*(\"\s*.*)$/$1$2/;
  235.         }
  236.         print $output->{$ip}{"lpd"}{$uriext};
  237.     }
  238.     } elsif ($output->{$ip}{"ipp"}) {
  239.     foreach my $uriext (keys(%{$output->{$ip}{"ipp"}})) {
  240.         if ($uriext =~ /^(printers|classes)\/(\S+)$/) {
  241.         # Queue from a CUPS server. We should suppress it if it
  242.         # is a queue received via CUPS broadcast
  243.         $queue=$2;
  244.         if (defined($localqueues->{"$queue\@$ip"})) {
  245.             $queue = "$queue\@$ip";
  246.         } elsif (defined($localqueues->{"$queue\@$hosts->{$ip}"})) {
  247.             $queue = "$queue\@$hosts->{$ip}";
  248.         }
  249.         if (defined($localqueues->{$queue})) {
  250.             if ($localqueues->{$queue}{remote} &&
  251.             ($localqueues->{$queue}{uri} =~
  252.              /^ipp:\/\/([^\/:]+)(:\d+|)\/(\S+)/)) {
  253.             my $host = $1;
  254.             my $ue = $3;
  255.             if ($host !~ /\d+\.\d+\.\d+\.\d+/) {
  256.                 $host =
  257.                 join(".", unpack("C4", gethostbyname($host)));
  258.             }
  259.             next if ($host eq $ip) && ($ue eq $uriext);
  260.             }
  261.         }
  262.         }
  263.         if (keys(%{$output->{$ip}{"ipp"}}) == 1) {
  264.         $output->{$ip}{"ipp"}{$uriext} =~
  265.             s/^(\s*\S*\s*\S*\s*\"[^\"]*\"\s*\"[^\"]*?)\s*\([^\)]*\)\s*(\"\s*.*)$/$1$2/;
  266.         }
  267.         print $output->{$ip}{"ipp"}{$uriext};
  268.     }
  269.     }
  270. }
  271.  
  272. exit 0;
  273.  
  274. # member( $a, @b ) returns 1 if $a is in @b, 0 otherwise.
  275. sub member { my $e = shift; foreach (@_) { $e eq $_ and return 1 } 0 };
  276.